﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Engine.Dtd.Schema;
using System.Runtime.InteropServices;
using System.Diagnostics;

namespace Engine.Sgml.Matching {
    [DebuggerDisplay("Element = {Element} Model = {Model}")]
    [StructLayout(LayoutKind.Auto)]
    internal struct CaptureEntity {
        [DebuggerBrowsable(DebuggerBrowsableState.Never)]
        private IModelGroupsNode model;
        [DebuggerBrowsable(DebuggerBrowsableState.Never)]
        private SElement element;
        [DebuggerBrowsable(DebuggerBrowsableState.Never)]
        private Match match;
        [DebuggerBrowsable(DebuggerBrowsableState.Never)]
        private int index;

        internal CaptureEntity(IModelGroupsNode model, SElement element) {
            Guard.ArgumentNotNull(model, "model");
            Guard.ArgumentNotNull(element, "element");
            this.model = model;
            this.element = element;
            this.match = null;
            this.index = element.OrderIndex;
            }

        internal CaptureEntity(SElement element) {
            Guard.ArgumentNotNull(element, "element");
            this.model = null;
            this.element = element;
            this.match = null;
            this.index = element.OrderIndex;
            }

        internal CaptureEntity(IModelGroupsNode model) {
            Guard.ArgumentNotNull(model, "model");
            this.model = model;
            this.element = null;
            this.match = null;
            this.index = 0;
            }

        internal CaptureEntity(Match match) {
            Guard.ArgumentNotNull(match, "match");
            this.model = match.Model;
            this.element = null;
            this.match = match;
            this.index = match.StartIndex;
            }

        /// <summary>
        /// Gets the model of the captured entity.
        /// </summary>
        public IModelGroupsNode Model { get { return model; } }
        /// <summary>
        /// Gets the captured element from the sequence of nodes.
        /// </summary>
        public SElement Element { get { return element; } }
        /// <summary>
        /// Get the match of captured elements from the sequence of nodes.
        /// </summary>
        public Match Match { get { return match; } }
        /// <summary>
        /// Gets the position in the elements sequence where the capture entity was found.
        /// </summary>
        public int Index { get { return index; } }

        public bool IsElement {
            get { return !object.ReferenceEquals(element, null); }
            }

        public bool IsIllegalElement {
            get { return object.ReferenceEquals(model, null) && IsElement; }
            }

        public bool IsModelMatch {
            get { return match != null; }
            }

        public bool IsInclusion {
            get { return object.ReferenceEquals(InclusionNode.Instance, model) && IsElement; }
            }

        internal void Move(Match parent, SElement ancestor, int index) {
            if (IsModelMatch) {
                for (int i = 0; i < this.match.Captures.Count; i++) {
                    Capture capture = this.match.Captures[i];
                    if (capture.Success) {
                        CaptureEntity e = capture.Entity;
                        e.Move(this.match, ancestor, index);
                        if (e.IsElement)
                            index++;
                        else
                            index = e.Match.NextIndex;
                        }
                    }
                this.match.Parent = parent;
                }
            else if (IsElement) {
                if (object.ReferenceEquals(element.Parent, ancestor)) {
                    element.Move(index);
                    }
                else {
                    //element.Remove();
                    //ancestor.Nodes.Insert(element, index);
                    //element.Parent = ancestor;
                    ancestor.Nodes[index].AddBeforeSelf(element);
                    }
                }
            else
                throw new InvalidOperationException("Cann't move the capture entity.");
            }
        }
    }
